#include "include.h"

void par_init(void)
{
	int __x = 0;
	int __y = 15;

	for (int i = 0; i < par_num; i++)
	{
		// 顺序排列
		__x += 15;
		if (__x + 15 > WIN_W)
		{
			__x = 15;
			__y += 15;
		}

		particles[i].x = __x;					  // 随机初始化x坐标
		particles[i].y = __y;					  // 随机初始化y坐标
		particles[i].vx = 0;					  // 随机初始化x方向速度
		particles[i].vy = 0;					  // 随机初始化y方向速度
		particles[i].ax = 0;					  // 初始化x方向加速度
		particles[i].ay = 0;					  // 初始化y方向加速度
		particles[i].R = (rand() % 200) / 256.0f; // 随机初始化颜色R
		particles[i].G = (rand() % 200) / 256.0f; // 随机初始化颜色G
		particles[i].B = (rand() % 200) / 256.0f; // 随机初始化颜色B
	}
}

struct regional regionals[REGIONAL_Y][REGIONAL_X];

void calculate_regional_acc(void)
{
	int x, y;
	struct regional *p;

	p = &regionals[0][0];
	memset(regionals, 0, sizeof(regionals));

	for (int i = 0; i < par_num; i++)
	{
		x = particles[i].x / GridRatio;
		y = particles[i].y / GridRatio;

		if (x >= 0 && x <= REGIONAL_X - 1 &&
			y >= 0 && y <= REGIONAL_Y - 1)
		{
			regionals[y][x].par_num++;
		}
	}

	for (int j = 0; j < sizeof(regionals) / sizeof(struct regional); j++)
	{
		if (p[j].par_num == 0)
		{
			continue;
		}

		for (int i = 0; i < sizeof(regionals) / sizeof(struct regional); i++)
		{
			int jx, jy;
			int ix, iy;
			int dx, dy;
			float dis_2;

			if (!p[i].par_num || j == i)
			{
				continue;
			}

			jy = j / REGIONAL_X;
			jx = j % REGIONAL_X;
			iy = i / REGIONAL_X;
			ix = i % REGIONAL_X;
			dx = (jx - ix) * GridRatio;
			dy = (jy - iy) * GridRatio;
			dis_2 = dx * dx + dy * dy;

			p[i].ax += p[j].par_num * -5 * dx / dis_2;
			p[i].ay += p[j].par_num * -5 * dy / dis_2;
		}
	}
}

void calculate_exclusion(float dx, float dy, float distance_2, float distance, Particle *particle)
{
	float exclude_ax;								   // 排斥作用的加速度x
	float exclude_ay;								   // 排斥作用的加速度y
	if (distance_2 < distance * distance)			   // 距离比对
	{												   // 只计算小于distance距离内的粒子
		double dis_8 = pow(distance_2, 4);			   // 计算距离的8次方
		exclude_ax = 20000000000 * dx / dis_8;		   // 计算x排斥力
		exclude_ay = 20000000000 * dy / dis_8;		   // 计算y排斥力
		exclude_ax = LIMIT(exclude_ax, -MAX_A, MAX_A); // 限制x排斥力大小
		exclude_ay = LIMIT(exclude_ay, -MAX_A, MAX_A); // 限制y排斥力大小
		particle->ax += exclude_ax;					   // 合并x排斥力加速度
		particle->ay += exclude_ay;					   // 合并y排斥力加速度
	}
}

void calculate_acceleration(int start, int end)
{
	for (int j = start; j < end; j++)
	{
		float dx;		  // 两个粒子之间的x距离
		float dy;		  // 两个粒子之间的y距离
		float distance_2; // 两个粒子之间距离的平方

		particles[j].ax = xa_g; // 初始x加速度
		particles[j].ay = ya_g; // 初始y加速度
		for (int i = 0; i < par_num; i++)
		{
			if (i == j) // 跳过计算相同的粒子
			{
				continue;
			}

			// 计算加速度
			dx = particles[j].x - particles[i].x;						// 计算两个粒子之间的x距离
			dy = particles[j].y - particles[i].y;						// 计算两个粒子之间的y距离
			distance_2 = dx * dx + dy * dy;								// 计算两个粒子之间距离的平方
			if (distance_2 < 0.01)										// 防止两个球距离太近
			{															// 和防止两个球位置一样导致排斥力与吸引力无穷大的尴尬情况
				particles[j].x += 0.01 * ((rand() % 100) + 10);			// 微小随机偏移x位置
				particles[j].y += 0.01 * ((rand() % 100) + 10);			// 微小随机偏移y位置
				dx = particles[j].x - particles[i].x;					// 重新计算x的差距
				dy = particles[j].y - particles[i].y;					// 重新计算y的差距
				distance_2 = dx * dx + dy * dy;							// 计算距离的平方
			}															// 距离太近时两个球会出现类似炸开的效果 (离谱)
			particles[j].ax += -5 * dx / distance_2;					// 计算x吸引力
			particles[j].ay += -5 * dy / distance_2;					// 计算y吸引力
			calculate_exclusion(dx, dy, distance_2, 30, &particles[j]); // 计算排斥力
		}

		dx = particles[j].x;										// 计算粒子到左边界的距离
		dy = 0;														// 留空
		distance_2 = dx * dx + dy * dy;								// 计算距离的平方
		calculate_exclusion(dx, dy, distance_2, 30, &particles[j]); // 计算排斥力

		dx = particles[j].x - WIN_W;								// 计算粒子到右边界的距离
		dy = 0;														// 留空
		distance_2 = dx * dx + dy * dy;								// 计算距离的平方
		calculate_exclusion(dx, dy, distance_2, 30, &particles[j]); // 计算排斥力

		dx = 0;														// 留空
		dy = particles[j].y;										// 计算粒子到上边界的距离
		distance_2 = dx * dx + dy * dy;								// 计算距离的平方
		calculate_exclusion(dx, dy, distance_2, 30, &particles[j]); // 计算排斥力

		dx = 0;														// 留空
		dy = particles[j].y - WIN_H;								// 计算粒子到下边界的距离
		distance_2 = dx * dx + dy * dy;								// 计算距离的平方
		calculate_exclusion(dx, dy, distance_2, 30, &particles[j]); // 计算排斥力
	}
}

void calculate_location(void)
{
	// 遍历所有粒子
	for (int j = 0; j < par_num; j++)
	{
		// 处理边界碰撞
		// 如果粒子在边界内部,则保持原速度与加速度方向不变;如果粒子在边界外部,则速度与加速度方向取反
		particles[j].vx = ((particles[j].x < 0 && particles[j].vx < 0) || particles[j].x > WIN_W && particles[j].vx > 0) ? (-particles[j].vx) : (particles[j].vx);
		particles[j].vy = ((particles[j].y < 0 && particles[j].vy < 0) || particles[j].y > WIN_H && particles[j].vy > 0) ? (-particles[j].vy) : (particles[j].vy);
		particles[j].ax = ((particles[j].x < 0 && particles[j].ax < 0) || particles[j].x > WIN_W && particles[j].ax > 0) ? (-particles[j].ax) : (particles[j].ax);
		particles[j].ay = ((particles[j].y < 0 && particles[j].ay < 0) || particles[j].y > WIN_H && particles[j].ay > 0) ? (-particles[j].ay) : (particles[j].ay);

		// 模拟粒子运动
		// 根据加速度更新速度,再根据速度更新位置
		particles[j].vx += particles[j].ax * TIME_DT; // 计算速度
		particles[j].vy += particles[j].ay * TIME_DT; // 计算速度
		particles[j].vx *= 0.995;					  // 添加阻尼,减小速度
		particles[j].vy *= 0.995;					  // 添加阻尼,减小速度
		particles[j].x += particles[j].vx * TIME_DT;  // 计算位置
		particles[j].y += particles[j].vy * TIME_DT;  // 计算位置
	}
}
